package ar.com.e2solver.conf;

import java.awt.Color;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import ar.com.e2solver.exception.BusinessException;
import ar.com.e2solver.model.Piece;

public class PuzzleTheme {

	private Piece[][] pieces;
	private List<Color> availableColors;
	private Integer rows;
	private Integer cols;

	public PuzzleTheme() throws BusinessException {

		InputStream is = null;
		try {
			 is = this.getClass().getResourceAsStream("/samples/e2pieces.txt");
	 
			 //is = this.getClass().getResourceAsStream("/samples/pieces_04x04.txt");
			 //is = this.getClass().getResourceAsStream("/samples/pieces_05x05.txt");
			 //is = this.getClass().getResourceAsStream("/samples/pieces_06x06.txt");
			 //is = this.getClass().getResourceAsStream("/samples/pieces_07x07.txt");
			 //is = this.getClass().getResourceAsStream("/samples/pieces_10x10.txt");
			//is = this.getClass().getResourceAsStream("/samples/pieces_12x12.txt");
			//is = this.getClass().getResourceAsStream("/samples/pieces_14x14.txt");
			load(is);
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (Exception e) {
				}
			}
		}
	}

	public PuzzleTheme(File file) throws BusinessException {

		InputStream is = null;
		try {
			is = new FileInputStream(file);
			load(is);
		} catch (IOException e) {
			throw new BusinessException("No se puede cargar el archivo");
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (Exception e) {
				}
			}
		}
	}
	
	public PuzzleTheme(InputStream is) throws BusinessException {
		load(is);
	}

	/**
	 * Lee de un inputStream el rompecabezas. Los primeros dos renglones son el
	 * numero de filas y columnas respectivamente y luego una pieza por renglon
	 * 
	 * @param is
	 * @throws BusinessException
	 */
	private void load(InputStream is) throws BusinessException {
		this.availableColors = getColors();
		InputStreamReader ir = null;
		BufferedReader br = null;

		try {
			ir = new InputStreamReader(is);
			br = new BufferedReader(ir);

			// Primeros dos renglones tienen la cantidad de filas y columnas
			this.rows = Integer.parseInt(br.readLine());
			this.cols = Integer.parseInt(br.readLine());

			// Levanta las fichas
			this.pieces = new Piece[this.getRows()][this.getCols()];
			String strLine;
			int currentRow = 0;
			int currentCol = 0;
			int pieceNumber = 0;
			while ((strLine = br.readLine()) != null) {
				String[] piecesParts = strLine.split(" ");
				Color top = getColor(piecesParts[0]);
				Color right = getColor(piecesParts[1]);
				Color bottom = getColor(piecesParts[2]);
				Color left = getColor(piecesParts[3]);

				Piece piece = new Piece(left, top, right, bottom, pieceNumber);
				pieces[currentRow][currentCol] = piece;

				if (currentCol == this.getCols() - 1) {
					currentCol = 0;
					currentRow++;
				} else {
					currentCol++;
				}
				pieceNumber++;
			}

			if (currentCol != 0 || currentRow != this.getRows()) {
				throw new BusinessException(
						"La cantidad de piezas no corresponde a un tablero de "
								+ this.getRows() + "x" + this.getCols());
			}

		} catch (IOException e) {
			throw new BusinessException("Error parseando el archivo del rompecabezas", e);
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (Exception e) {
				}
			}
			if (ir != null) {
				try {
					ir.close();
				} catch (Exception e) {
				}
			}
		}
	}

	private Color getColor(String colorNumber) {
		return this.availableColors.get(Integer.parseInt(colorNumber));
	}

	/**
	 * Devuelve una copia de la pieza que se ubica en la posicion ij.
	 * 
	 * @param i
	 * @param j
	 * @return
	 */
	public Piece getPiece(int i, int j) {
		return this.pieces[i][j].clone();
	}

	/**
	 * Colores disponibles para los rompecabezas
	 * 
	 * @return
	 */
	private static List<Color> getColors() {
		List<Color> colors = new ArrayList<Color>();
		colors.add(Piece.BORDER_COLOR);
		colors.add(new Color(50, 0, 0));
		colors.add(new Color(0, 50, 0));
		colors.add(new Color(0, 0, 50));
		colors.add(new Color(50, 50, 0));
		colors.add(new Color(50, 0, 50));
		colors.add(new Color(0, 50, 50));
		colors.add(new Color(100, 0, 0));
		colors.add(new Color(0, 100, 0));
		colors.add(new Color(0, 0, 100));
		colors.add(new Color(100, 100, 0));
		colors.add(new Color(100, 0, 100));
		colors.add(new Color(0, 100, 100));
		colors.add(new Color(150, 0, 0));
		colors.add(new Color(0, 150, 0));
		colors.add(new Color(0, 0, 150));
		colors.add(new Color(150, 150, 0));
		colors.add(new Color(150, 0, 150));
		colors.add(new Color(0, 150, 150));
		colors.add(new Color(200, 0, 0));
		colors.add(new Color(0, 200, 0));
		colors.add(new Color(0, 0, 200));
		colors.add(new Color(200, 200, 0));
		colors.add(new Color(0, 200, 200));
		colors.add(new Color(250, 0, 0));
		colors.add(new Color(0, 250, 0));
		colors.add(new Color(0, 0, 250));
		colors.add(new Color(250, 250, 0));
		colors.add(new Color(0, 250, 250));
		return colors;
	}
	
	public static int getNumberForColor(Color c){
		return getColors().indexOf(c);
	}

	public Integer getRows() {
		return this.rows;
	}

	public Integer getCols() {
		return this.cols;
	}

}
